<template>
	<div class="card filter">
		<h4 class="title sle" v-if="title">{{ title }}</h4>
		<div class="flex">
			<el-input v-model="filterText" :placeholder="$t('treefilter.placeholder.filter')" clearable class="flex-1" />
			<el-switch v-model="checkStrictly" class="w-24 ml-4" :inactive-text="$t('treefilter.inactive_text.cascade')" />
		</div>
		<el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }">
			<el-tree
				ref="treeRef"
				default-expand-all
				:node-key="props.id"
				:data="multiple ? treeData : treeAllData"
				:show-checkbox="multiple"
				:check-strictly="!checkStrictly"
				:current-node-key="!multiple ? selected : ''"
				:highlight-current="!multiple"
				:expand-on-click-node="false"
				:check-on-click-node="multiple"
				:props="defaultProps"
				:filter-node-method="filterNode"
				:default-checked-keys="multiple ? selected : []"
				@node-click="handleNodeClick"
				@check="handleCheckChange"
			/>
		</el-scrollbar>
	</div>
</template>

<script setup lang="ts" name="TreeFilter">
import { ref, watch, onBeforeMount } from "vue";
import { ElTree } from "element-plus";
import { TreeKey, TreeNodeData } from "element-plus/es/components/tree/src/tree.type";
const checkStrictly = ref(true);
// 接收父组件参数并设置默认值
interface TreeFilterProps {
	requestApi?: (data?: any) => Promise<any>; // 请求分类数据的 api ==> 非必传
	data?: { [key: string]: any }[]; // 分类数据，如果有分类数据，则不会执行 api 请求 ==> 非必传
	params?: { [key: string]: any };
	title?: string; // treeFilter 标题 ==> 非必传
	id?: string; // 选择的id ==> 非必传，默认为 “id”
	label?: string; // 显示的label ==> 非必传，默认为 “label”
	multiple?: boolean; // 是否为多选 ==> 非必传，默认为 false
	defaultValue?: string[] | string; // 默认选中的值 ==> 非必传
	dataCallback?: (data: any) => any; // 返回数据的回调函数，可以对数据进行处理 ==> 非必传
	isCheckStrictly?: boolean; //在显示复选框的情况下，是否严格的遵循父子不互相关联的做法，默认为 false
	clearable?: boolean;
}
const props = withDefaults(defineProps<TreeFilterProps>(), {
	id: "id",
	label: "label",
	multiple: false,
	isCheckStrictly: false,
	clearable: true
});

const defaultProps = {
	children: "children",
	label: props.label
};

const filterText = ref<string>("");
const treeRef = ref<InstanceType<typeof ElTree>>();
const treeData = ref<{ [key: string]: any }[]>([]);
const treeAllData = ref<{ [key: string]: any }[]>([]);
// 选中的值
const selected = ref();

onBeforeMount(async () => {
	init();
});

watch(filterText, val => {
	treeRef.value!.filter(val);
});
watch(
	() => props.isCheckStrictly,
	() => {
		checkStrictly.value = !props.isCheckStrictly;
	},
	{ immediate: true }
);
const init = async () => {
	// 重新接收一下默认值
	if (props.multiple) {
		selected.value = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue];
	} else {
		selected.value = typeof props.defaultValue === "string" ? props.defaultValue : "";
	}
	// 有数据就直接赋值，没有数据就执行请求函数
	if (props.data?.length) {
		treeData.value = props.data;
		treeAllData.value = props.data;
		return;
	}
	if (!props.requestApi) {
		return;
	}
	let { result } = await props.requestApi(props.params);
	props.dataCallback && (result = props.dataCallback(result));
	treeData.value = result;
	treeAllData.value = props.multiple ? [{ id: "", [props.label]: "全部" }, ...result] : result;
	//组件加载完成返回事件
	nextTick(() => {
		if (props.defaultValue) {
			let keys = Array.isArray(props.defaultValue) ? props.defaultValue : [props.defaultValue];
			treeRef.value!.setCheckedKeys(keys);
		}
		emit("treeRefMounted");
	});
};
// 过滤
const filterNode = (value: string, data: { [key: string]: any }, node: any) => {
	if (!value) return true;
	let parentNode = node.parent,
		labels = [node.label],
		level = 1;
	while (level < node.level) {
		labels = [...labels, parentNode.label];
		parentNode = parentNode.parent;
		level++;
	}
	return labels.some(label => label.indexOf(value) !== -1);
};

interface FilterEmits {
	(e: "change", value: any): void;
	(e: "treeRefMounted"): void;
}
const emit = defineEmits<FilterEmits>();

// 单选
const handleNodeClick = (data: { [key: string]: any }) => {
	if (props.multiple) return;
	emit("change", data);
};

// 多选
const handleCheckChange = () => {
	//返回选中的值和半选的值
	emit("change", { checked: treeRef.value?.getCheckedNodes(), halfChecked: treeRef.value?.getHalfCheckedNodes() });
};
// 多选
const handleAllChecked = (/* keyList: any = [],  */ nodeList: TreeNodeData[], checked: boolean, deep: boolean) => {
	nodeList.forEach((node: TreeKey | TreeNodeData) => {
		treeRef.value?.setChecked(node, checked, deep);
	});
	//返回选中的值和半选的值
	emit("change", { checked: checked ? nodeList : [], halfChecked: [] });
};
const getNode = (key: TreeKey | TreeNodeData) => {
	return treeRef.value?.getNode(key);
};

const getCheckedKeys = () => {
	let checked = treeRef.value?.getCheckedKeys();
	return checked;
};
const getCheckedNodes = () => {
	let checked = treeRef.value?.getCheckedNodes();
	return checked;
};
const getHalfCheckedKeys = () => {
	return treeRef.value?.getHalfCheckedKeys();
};
const setCheckedKeys = (kyes: any[]) => {
	return treeRef.value?.setCheckedKeys(kyes);
};
const setCheckedNodes = (kyes: any[]) => {
	return treeRef.value?.setCheckedNodes(kyes);
};
// 暴露给父组件使用
defineExpose({
	treeData,
	treeAllData,
	getNode,
	handleAllChecked,
	getCheckedKeys,
	getHalfCheckedKeys,
	setCheckedKeys,
	setCheckedNodes,
	getCheckedNodes
});
</script>

<style scoped lang="scss">
@import "./index.scss";
.assign-group {
	height: 55vh;
	max-height: 70vh;
}
</style>
